package com.sc.nft.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sc.nft.dao.*;
import com.sc.nft.dto.TradePoolConsumerDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.NurturingAwardIncomeDTO;
import com.sc.nft.entity.dto.SettleAmountDTO;
import com.sc.nft.entity.dto.TeamIncomeDTO;
import com.sc.nft.entity.dto.TeamUserPerformanceDTO;
import com.sc.nft.enums.*;
import com.sc.nft.enums.wallet.DaoWalletTypeEnum;
import com.sc.nft.enums.wallet.DepartmentTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 收益发放
 *
 * @author Sun
 * @since 2022-09-22 13:20:10
 */

@Slf4j
@RequiredArgsConstructor
@Service
public class IncomeServiceImpl implements IncomeService {

    private final TradingPoolOrderDao tradingPoolOrderDao;
    private final ShareProfitRatioDao shareProfitRatioDao;
    private final UserWalletDao userWalletDao;
    private final UserWalletDetailDao userWalletDetailDao;
    private final ExpenditureRecordDao expenditureRecordDao;
    private final OrderDao orderDao;
    private final SecondOrderDao secondOrderDao;
    private final UserInfoDao userInfoDao;
    private final ShareProfitPanelDao shareProfitPanelDao;
    private final UserIncomeRecordDao userIncomeRecordDao;
    private final SharePoolWeekDao sharePoolWeekDao;
    private final UserCollectionDao userCollectionDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final SecondCollectionConfigDao secondCollectionConfigDao;
    private final ShareProfitDao shareProfitDao;
    private final ExpenditureRecordService expenditureRecordService;
    private final ShareProfitDirectCollectionDao shareProfitDirectCollectionDao;
    private final StaticDataDao staticDataDao;
    private final UserDaoPerformanceDao userDaoPerformanceDao;
    private final UserCityServerCentreDao userCityServerCentreDao;
    private final UserWorkRoomDao userWorkRoomDao;
    private final UserRelevanceDao userRelevanceDao;
    private final UserMarketValueDao userMarketValueDao;
    private final DaoWalletService daoWalletService;
    private final DepartmentWalletService departmentWalletService;
    private final TradingPoolConfigService tradingPoolConfigService;
    private final OrderSettleDao orderSettleDao;
    private final SecondOrderSettleDao secondOrderSettleDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void firstDirectPushIncome(Order order) {
        Order newOrder = orderDao.getById(order);
        if (newOrder.getSettleFlag()) {
            return;
        }

        orderDao.allReadySettleFlag(order.getId());//更新订单结算状态

        ShareProfitPanel panel = shareProfitPanelDao.getById(order.getShareProfitPanelId());
        if (ObjectUtil.isNull(panel)) {
            log.warn("首发订单{}未配置分润模板", order.getOrderNo());
            return;
        }

        List<ShareProfit> shareProfitList = shareProfitDao.getByPanelId(panel.getId());
        for (ShareProfit shareProfit : shareProfitList) {
            switch (shareProfit.getDivideType()) {
                case DIRECT_PUSH://直推直接发出去
                    FirstOrderSettle orderSettle = new FirstOrderSettle();
                    orderSettle.setOrderId(order.getId());
                    orderSettle.setSumAmount(order.getProductPrice());
                    orderSettle.setRatio(shareProfit.getSumRatio());
                    orderSettle.setAllocationAmount(order.getProductPrice().multiply(shareProfit.getSumRatio()));
                    orderSettle.setDivideType(shareProfit.getDivideType());
                    orderSettle.setAllocationType(AllocationTypeEnum.DIRECT_PUSH);
                    orderSettle.setVestId(0L);
                    orderSettle.setIsSettle(true);
                    if (NumberUtil.equals(orderSettle.getSumAmount(), BigDecimal.ZERO)) {
                        orderSettle.setIsSettle(true);
                    } else {
                        List<Long> collectionIds = shareProfitDirectCollectionDao.getCollectionIdsByPanelId(order.getShareProfitPanelId());
                        if (CollUtil.isNotEmpty(collectionIds)) {//配置了直推关联藏品
                            UserInfo userInfo = userInfoDao.getById(order.getUserId());
                            if (userInfo.getBindFlag() && userInfo.getRecommendUserId() != 1) {//绑定过邀请码
                                if (userCollectionDao.userHasCollections(userInfo.getRecommendUserId(), collectionIds)) {//持有任意藏品
                                    orderSettle.setVestId(userInfo.getRecommendUserId());
                                    addMoney(orderSettle.getVestId(), order.getUserId(), order.getId(), order.getOrderNo(), orderSettle.getSumAmount(),
                                            orderSettle.getAllocationAmount(), shareProfit.getSumRatio(), IncomeTypeEnum.DIRECT_PURCHASE, IncomeHierarchyEnum.PUSH_STRAIGHT);
                                }
                            }
                        }
                    }
                    orderSettle.insert();
                    break;
                case DAO:
                    List<ShareProfitRatio> ratios = shareProfitRatioDao.getProfitId(shareProfit.getId());
                    for (ShareProfitRatio ratio : ratios) {
                        orderSettle = new FirstOrderSettle();
                        orderSettle.setOrderId(order.getId());
                        orderSettle.setSumAmount(order.getProductPrice());
                        orderSettle.setDivideType(DivideTypeEnum.DAO);
                        orderSettle.setRatio(shareProfit.getSumRatio().multiply(ratio.getShareRatio()));
                        orderSettle.setAllocationAmount(order.getProductPrice().multiply(orderSettle.getRatio()));
                        orderSettle.setAllocationType(ratio.getAllocationPoolType());
                        orderSettle.setVestId(shareProfit.getDaoId());
                        orderSettle.setIsSettle(true);
                        if (!NumberUtil.equals(orderSettle.getAllocationAmount(), BigDecimal.ZERO)) {
                            switch (orderSettle.getAllocationType()) {
                                case BUSINESS:
                                    departmentWalletService.addBalance(DepartmentTypeEnum.BUSINESS, MarketLevelEnum.FIRST, order.getOrderNo(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case PROJECT:
                                    departmentWalletService.addBalance(DepartmentTypeEnum.PROJECT, MarketLevelEnum.FIRST, order.getOrderNo(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case COMPANY:
                                    daoWalletService.addBalance(shareProfit.getDaoId(), order.getId(), orderSettle.getAllocationAmount(), BigDecimal.ZERO, DaoWalletTypeEnum.FIRST_SELL_COLLECTION, DaoWalletTypeEnum.FIRST_SELL_COLLECTION.getDescription());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case GIFT:
                                    tradingPoolConfigService.addGiftIncomeAccount(shareProfit.getDaoId(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                default:
                                    orderSettle.setIsSettle(false);
                                    break;
                            }
                        }
                        orderSettle.insert();
                    }
                    break;
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void secondDirectPushIncome(SecondOrder order) {
        SecondOrder newOrder = secondOrderDao.getById(order.getId());
        if (newOrder.getSettleFlag()) {
            return;
        }


        ShareProfitPanel panel = shareProfitPanelDao.getById(order.getShareProfitPanelId());
        if (ObjectUtil.isNull(panel)) {
            log.warn("二级订单{}未配置分润模板", order.getOrderNo());
            return;
        }

        List<ShareProfit> shareProfitList = shareProfitDao.getByPanelId(panel.getId());
//        log.info("2-二级藏品直推奖励权益模版：{}", JSONArray.toJSONString(shareProfitList));
        for (ShareProfit shareProfit : shareProfitList) {
            switch (shareProfit.getDivideType()) {
                case DIRECT_PUSH://直推直接发出去
//                    log.info("系统余额支付二级订单的直推~~~~~~~~~~");
                    SecondOrderSettle orderSettle = new SecondOrderSettle();
                    orderSettle.setOrderId(order.getId());
                    orderSettle.setSumAmount(order.getCharge());
                    orderSettle.setRatio(shareProfit.getSumRatio());
                    orderSettle.setAllocationAmount(order.getCharge().multiply(shareProfit.getSumRatio()));
                    orderSettle.setDivideType(shareProfit.getDivideType());
                    orderSettle.setAllocationType(AllocationTypeEnum.DIRECT_PUSH);
                    orderSettle.setVestId(0L);
                    orderSettle.setIsSettle(true);
                    if (NumberUtil.equals(orderSettle.getSumAmount(), BigDecimal.ZERO)) {
                        orderSettle.setIsSettle(true);
                    } else {
                        List<Long> collectionIds = shareProfitDirectCollectionDao.getCollectionIdsByPanelId(order.getShareProfitPanelId());
                        if (CollUtil.isNotEmpty(collectionIds)) {//配置了直推关联藏品
                            UserInfo userInfo = userInfoDao.getById(order.getBuyUserId());
                            if (userInfo.getBindFlag() && userInfo.getRecommendUserId().longValue() != 1) {//绑定过邀请码
                                if (userCollectionDao.userHasCollections(userInfo.getRecommendUserId(), collectionIds)) {//持有任意藏品
                                    orderSettle.setVestId(userInfo.getRecommendUserId());
                                    addMoney(orderSettle.getVestId(), order.getBuyUserId(), order.getId(), order.getOrderNo(), orderSettle.getSumAmount(),
                                            orderSettle.getAllocationAmount(), shareProfit.getSumRatio(), IncomeTypeEnum.DIRECT_PURCHASE_FEE, IncomeHierarchyEnum.PUSH_STRAIGHT);
                                }
                            }
                        }
                    }
//                    orderSettle.insert();
                    secondOrderSettleDao.save(orderSettle);
                    break;
                case DAO:
                    List<ShareProfitRatio> ratios = shareProfitRatioDao.getProfitId(shareProfit.getId());
                    for (ShareProfitRatio ratio : ratios) {
                        orderSettle = new SecondOrderSettle();
                        orderSettle.setOrderId(order.getId());
                        orderSettle.setSumAmount(order.getCharge());
                        orderSettle.setDivideType(DivideTypeEnum.DAO);
                        orderSettle.setRatio(shareProfit.getSumRatio().multiply(ratio.getShareRatio()));
                        orderSettle.setAllocationAmount(order.getCharge().multiply(orderSettle.getRatio()));
                        orderSettle.setAllocationType(ratio.getAllocationPoolType());
                        orderSettle.setVestId(shareProfit.getDaoId());
                        if (NumberUtil.equals(orderSettle.getAllocationAmount(), BigDecimal.ZERO)) {
                            orderSettle.setIsSettle(true);
                        } else {
                            switch (orderSettle.getAllocationType()) {
                                case BUSINESS:
                                    departmentWalletService.addBalance(DepartmentTypeEnum.BUSINESS, MarketLevelEnum.SECOND, order.getOrderNo(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case PROJECT:
                                    departmentWalletService.addBalance(DepartmentTypeEnum.PROJECT, MarketLevelEnum.SECOND, order.getOrderNo(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case COMPANY:
                                    daoWalletService.addBalance(shareProfit.getDaoId(), order.getId(), orderSettle.getAllocationAmount(), BigDecimal.ZERO, DaoWalletTypeEnum.SECOND_SELL_COLLECTION, DaoWalletTypeEnum.SECOND_SELL_COLLECTION.getDescription());
                                    orderSettle.setIsSettle(true);
                                    break;
                                default:
                                    orderSettle.setIsSettle(false);
                                    break;
                            }
                        }
//                        orderSettle.insert();
                        secondOrderSettleDao.save(orderSettle);
                    }
                    break;
            }
        }
    }

    //TODO 改造直推发放
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void secondDirectPushIncomeForSplit(SecondOrder order, List<SettleAmountDTO> amountDTOS) {
        SecondOrder newOrder = secondOrderDao.getById(order.getId());
        if (newOrder.getSettleFlag()) {
            return;
        }


        ShareProfitPanel panel = shareProfitPanelDao.getById(order.getShareProfitPanelId());
        if (ObjectUtil.isNull(panel)) {
            log.warn("二级订单{}未配置分润模板", order.getOrderNo());
            return;
        }

        List<ShareProfit> shareProfitList = shareProfitDao.getByPanelId(panel.getId());
//        log.info("2-二级藏品直推奖励权益模版：{}", JSONArray.toJSONString(shareProfitList));
        for (ShareProfit shareProfit : shareProfitList) {
            switch (shareProfit.getDivideType()) {
                case DIRECT_PUSH://直推直接发出去
//                    log.info("3-二级藏品直推奖励计算开始");
                    SecondOrderSettle orderSettle = new SecondOrderSettle();
                    orderSettle.setOrderId(order.getId());
                    orderSettle.setSumAmount(order.getCharge());
                    orderSettle.setRatio(shareProfit.getSumRatio());
                    orderSettle.setAllocationAmount(order.getCharge().multiply(shareProfit.getSumRatio()).setScale(2, RoundingMode.HALF_DOWN));
                    orderSettle.setDivideType(shareProfit.getDivideType());
                    orderSettle.setAllocationType(AllocationTypeEnum.DIRECT_PUSH);
                    orderSettle.setVestId(0L);
                    orderSettle.setIsSettle(true);
                    if (!NumberUtil.equals(orderSettle.getSumAmount(), BigDecimal.ZERO)) {
                        List<Long> collectionIds = shareProfitDirectCollectionDao.getCollectionIdsByPanelId(order.getShareProfitPanelId());
                        if (CollUtil.isNotEmpty(collectionIds)) {//配置了直推关联藏品
                            UserInfo userInfo = userInfoDao.getById(order.getBuyUserId());
                            if (userInfo.getBindFlag() && userInfo.getRecommendUserId().longValue() != 1) {//绑定过邀请码
                                if (userCollectionDao.userHasCollections(userInfo.getRecommendUserId(), collectionIds)) {//持有任意藏品
                                    orderSettle.setVestId(userInfo.getRecommendUserId());
                                    //TODO 2024-10-24 分账改造新增结算单、待结算金额 走定时任务发放
                                    addMoneyForSplit(orderSettle.getVestId(), order.getBuyUserId(), order.getId(), order.getOrderNo(), orderSettle.getSumAmount(),
                                            orderSettle.getAllocationAmount(), shareProfit.getSumRatio(),
                                            IncomeTypeEnum.DIRECT_PURCHASE_FEE, IncomeHierarchyEnum.PUSH_STRAIGHT
                                            , WalletDetailTypeEnum.DIRECT_PURCHASE, amountDTOS, ExpenditureRecordTypeEnum.SHARE_AMOUNT);
                                }
                            }
                        }
                    }
//                    orderSettle.insert();
                    secondOrderSettleDao.save(orderSettle);
//                    log.info("4-二级藏品直推奖励计算结束，生成SC_ORDER_SETTLE:{}", JSONObject.toJSONString(orderSettle));
                    break;
                case DAO:
                    List<ShareProfitRatio> ratios = shareProfitRatioDao.getProfitId(shareProfit.getId());
                    for (ShareProfitRatio ratio : ratios) {
                        orderSettle = new SecondOrderSettle();
                        orderSettle.setOrderId(order.getId());
                        orderSettle.setSumAmount(order.getCharge());
                        orderSettle.setDivideType(DivideTypeEnum.DAO);
                        orderSettle.setRatio(shareProfit.getSumRatio().multiply(ratio.getShareRatio()));
                        orderSettle.setAllocationAmount(order.getCharge().multiply(orderSettle.getRatio()));
                        orderSettle.setAllocationType(ratio.getAllocationPoolType());
                        orderSettle.setVestId(shareProfit.getDaoId());
                        if (NumberUtil.equals(orderSettle.getAllocationAmount(), BigDecimal.ZERO)) {
                            orderSettle.setIsSettle(true);
                        } else {
                            switch (orderSettle.getAllocationType()) {
                                case BUSINESS:
                                    departmentWalletService.addBalance(DepartmentTypeEnum.BUSINESS, MarketLevelEnum.SECOND, order.getOrderNo(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case PROJECT:
                                    departmentWalletService.addBalance(DepartmentTypeEnum.PROJECT, MarketLevelEnum.SECOND, order.getOrderNo(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case COMPANY:
                                    daoWalletService.addBalance(shareProfit.getDaoId(), order.getId(), orderSettle.getAllocationAmount(), BigDecimal.ZERO, DaoWalletTypeEnum.SECOND_SELL_COLLECTION, DaoWalletTypeEnum.SECOND_SELL_COLLECTION.getDescription());
                                    orderSettle.setIsSettle(true);
                                    break;
                                case GIFT:
                                    tradingPoolConfigService.addGiftIncomeAccount(shareProfit.getDaoId(), orderSettle.getAllocationAmount());
                                    orderSettle.setIsSettle(true);
                                    break;
                                default:
                                    orderSettle.setIsSettle(false);
                                    break;
                            }
                        }
//                        orderSettle.insert();
                        secondOrderSettleDao.save(orderSettle);
                    }
                    break;
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void tradePoolIncome(TradePoolConsumerDTO tradePoolConsumer) {
        TradingPoolOrder order = tradingPoolOrderDao.getById(tradePoolConsumer.getTradeOrderId());
        if (order.getShareSettleFlag()) {
            return;
        }

        int i = tradingPoolOrderDao.allReadySettleFlag(order.getVersion(), Boolean.TRUE, order.getId());//更新订单结算状态
        if (i <= 0) {
            throw new GlobalRunTimeException("交易池分润结算失败:" + tradePoolConsumer.getTradeOrderId());
        }


        ShareProfitPanel panel = shareProfitPanelDao.getById(order.getShareProfitPanelId());
        if (ObjectUtil.isNull(panel)) {
            log.warn("交易池{}未配置分润模板", order.getOrderNo());
            return;
        }

        List<ShareProfit> shareProfitList = shareProfitDao.getByPanelId(panel.getId());
        for (ShareProfit shareProfit : shareProfitList) {
            if (Objects.requireNonNull(shareProfit.getDivideType()) != DivideTypeEnum.DAO) {
                continue;
            }
            List<ShareProfitRatio> ratios = shareProfitRatioDao.getProfitId(shareProfit.getId());
            for (ShareProfitRatio ratio : ratios) {
                TradingPoolOrderSettle orderSettle = new TradingPoolOrderSettle();
                orderSettle.setOrderId(order.getId());
                orderSettle.setSumAmount(order.getCharge());
                orderSettle.setDivideType(DivideTypeEnum.DAO);
                orderSettle.setRatio(shareProfit.getSumRatio().multiply(ratio.getShareRatio()));
                orderSettle.setAllocationAmount(order.getCharge().multiply(orderSettle.getRatio()));
                orderSettle.setAllocationType(ratio.getAllocationPoolType());
                orderSettle.setVestId(shareProfit.getDaoId());
                if (NumberUtil.equals(orderSettle.getAllocationAmount(), BigDecimal.ZERO)) {
                    orderSettle.setIsSettle(true);
                } else {
                    switch (orderSettle.getAllocationType()) {
                        case BUSINESS:
                            departmentWalletService.addBalance(DepartmentTypeEnum.BUSINESS, MarketLevelEnum.TRANS_POOL, order.getOrderNo(), orderSettle.getAllocationAmount());
                            orderSettle.setIsSettle(true);
                            break;
                        case PROJECT:
                            departmentWalletService.addBalance(DepartmentTypeEnum.PROJECT, MarketLevelEnum.TRANS_POOL, order.getOrderNo(), orderSettle.getAllocationAmount());
                            orderSettle.setIsSettle(true);
                            break;
                        case COMPANY:
                            daoWalletService.addBalance(shareProfit.getDaoId(), order.getId(), orderSettle.getAllocationAmount(), BigDecimal.ZERO, DaoWalletTypeEnum.TRANS_POOL, DaoWalletTypeEnum.TRANS_POOL.getDescription());
                            orderSettle.setIsSettle(true);
                            break;
                        case GIFT:
                            tradingPoolConfigService.addGiftIncomeAccount(shareProfit.getDaoId(), orderSettle.getAllocationAmount());
                            orderSettle.setIsSettle(true);
                            break;
                        default:
                            orderSettle.setIsSettle(false);
                            break;
                    }
                }
                orderSettle.insert();
            }
        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void contributionAward(DaoShareConfig daoShareConfig, String yearWeek) {
        DateTime startTime = DateUtil.offsetDay(DateTime.now(), -daoShareConfig.getCalDuration());
        String startDate = startTime.toString("yyyyMMdd");
        List<SharePoolWeek> sharePoolWeeks = sharePoolWeekDao.getWaitSettleByType(daoShareConfig.getDaoId(), yearWeek, daoShareConfig.getAwardsType());
        if (CollUtil.isEmpty(sharePoolWeeks)) {
            return;
        }
        List<Long> userIds = userCollectionDao.getUserIdByHoldCollectionId(daoShareConfig.getIdentityCollectionId());
        List<TeamIncomeDTO> list = Lists.newArrayList();
        for (Long userId : userIds) {
            List<Long> holdUsers = userCollectionDao.getJuniorHoldCollectionCountByCollectionIds(userId, Lists.newArrayList(daoShareConfig.getPushCollectionId()));
            if (holdUsers.size() < daoShareConfig.getHoldUserCount()) {
                continue;
            }
            List<Long> downUserIds = userInfoDao.getDownUserIds(userId);
            List<TeamUserPerformanceDTO> daoSumPerformance = userDaoPerformanceDao.getDaoSumPerformance(daoShareConfig.getDaoId(), downUserIds, startDate);
            if (CollUtil.isEmpty(daoSumPerformance)) {
                log.warn("用户{}无下级业绩", userId);
                continue;
            }
            TeamIncomeDTO teamIncomeDTO = new TeamIncomeDTO();
            teamIncomeDTO.setUserId(userId);
            teamIncomeDTO.setCount(holdUsers.size());
            teamIncomeDTO.setTotalTransaction(daoSumPerformance.stream().map(TeamUserPerformanceDTO::getSumPerformance).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
            teamIncomeDTO.setMaxTotalTransaction(CollUtil.max(daoSumPerformance.stream().map(TeamUserPerformanceDTO::getSumPerformance).collect(Collectors.toList())));
            teamIncomeDTO.setValidTotalTransaction(teamIncomeDTO.getTotalTransaction().subtract(teamIncomeDTO.getMaxTotalTransaction()));
            list.add(teamIncomeDTO);
        }
        BigDecimal sumWeight = list.stream().map(TeamIncomeDTO::getValidTotalTransaction).reduce(BigDecimal::add).get();
        BigDecimal thisWeekSumAmount = BigDecimal.ZERO;
        for (SharePoolWeek sharePoolWeek : sharePoolWeeks) {
            if (NumberUtil.isGreater(sharePoolWeek.getSumAmount(), BigDecimal.ZERO)) {
                thisWeekSumAmount = thisWeekSumAmount.add(sharePoolWeek.getSumAmount().multiply(getDivRatio()).setScale(2, RoundingMode.FLOOR));
            }
            sharePoolWeek.setIsSettle(true);
            sharePoolWeek.updateById();
        }

        for (TeamIncomeDTO teamIncomeDTO : list) {
            BigDecimal ratio = teamIncomeDTO.getValidTotalTransaction().divide(sumWeight, 8, RoundingMode.FLOOR);
            BigDecimal sumAmount = thisWeekSumAmount.multiply(ratio).setScale(2, RoundingMode.FLOOR);
            BigDecimal balance = sumAmount.multiply(BigDecimal.valueOf(0.8)).setScale(2, RoundingMode.FLOOR);
            BigDecimal wishBalance = sumAmount.subtract(balance);
            IncomeTypeEnum incomeType = IncomeTypeEnum.TEAM_CONTRIBUTION_AWARD;
            IncomeHierarchyEnum incomeHierarchy = IncomeHierarchyEnum.SPECIAL;
            UserWallet wallet = userWalletDao.getByUserId(teamIncomeDTO.getUserId());
            addMoney(teamIncomeDTO.getUserId(), wallet, daoShareConfig.getId(), Long.parseLong(yearWeek), null,
                    thisWeekSumAmount, balance, ratio, incomeType, incomeHierarchy, daoShareConfig.getName(), sumWeight.toPlainString(), teamIncomeDTO.getValidTotalTransaction().toPlainString());
            addWishMoney(teamIncomeDTO.getUserId(), wallet, wishBalance, daoShareConfig.getName());
        }
    }

    private BigDecimal getDivRatio() {
        StaticData shareRatio = staticDataDao.getByType("share_ratio");
        if (ObjectUtil.isNull(shareRatio)) {
            return BigDecimal.valueOf(0.65);
        }
        return new BigDecimal(shareRatio.getValue());
    }


    private void addWishMoney(Long userId, UserWallet userWallet, BigDecimal amount, String shareConfigName) {
        UserWalletDetail wishDetail = new UserWalletDetail();
        wishDetail.setUserId(userId);
        wishDetail.setType(WalletDetailTypeEnum.ADD_WISH);
        wishDetail.setAmount(amount);
        wishDetail.setCharge(BigDecimal.ZERO);
        wishDetail.setBalanceType(UserBalanceTypeEnum.WISH_BALANCE);
        wishDetail.setRealAmount(wishDetail.getAmount());
        wishDetail.setAfterBalance(userWallet.getWishBalance().add(wishDetail.getAmount()));
        wishDetail.setBeforeBalance(userWallet.getWishBalance());
        wishDetail.setIsAdd(Boolean.TRUE);
        wishDetail.setRemark(shareConfigName);
        userWalletDetailDao.insert(wishDetail);
        userWalletDao.addWishBalance(userId, wishDetail.getAmount());
        expenditureRecordService.insertRecord(wishDetail.getUserId(), wishDetail.getAmount(), wishDetail.getCharge(), wishDetail.getRealAmount(), ExpenditureRecordTypeEnum.WISH_BALANCE_ADD,
                wishDetail.getBeforeBalance(), wishDetail.getAfterBalance(), null, ""
        );
    }

    private void addMoney(Long userId, Long sourceUserId, Long orderId, String orderNo, BigDecimal
            sumAmount, BigDecimal amount, BigDecimal ratio, IncomeTypeEnum incomeType, IncomeHierarchyEnum incomeHierarchy) {
        UserWallet wallet = userWalletDao.getByUserId(userId);
        addMoney(userId, wallet, sourceUserId, orderId, orderNo, sumAmount, amount, ratio, incomeType, incomeHierarchy, null, "0", "0");
    }

    //TODO 2024-10-24 分账改造
    private void addMoneyForSplit(Long userId, Long sourceUserId, Long orderId, String orderNo, BigDecimal
            sumAmount, BigDecimal amount, BigDecimal ratio, IncomeTypeEnum incomeType, IncomeHierarchyEnum incomeHierarchy, WalletDetailTypeEnum walletDetailTypeEnum,
                                  List<SettleAmountDTO> settleAmountDTOS, ExpenditureRecordTypeEnum expenditureRecordTypeEnum) {
        addMoneyForSplit(userId, sourceUserId, orderId, orderNo, sumAmount, amount, ratio, incomeType, incomeHierarchy,
                null, "0", "0", walletDetailTypeEnum, settleAmountDTOS, expenditureRecordTypeEnum);
    }

    private void addMoney(Long userId, UserWallet wallet, Long sourceUserId, Long orderId, String
            orderNo, BigDecimal sumAmount, BigDecimal amount, BigDecimal ratio, IncomeTypeEnum
                                  incomeType, IncomeHierarchyEnum incomeHierarchy, String remark, String weightNum, String incomeNum) {
        //收益幂等性校验
        UserIncomeRecord checkIncomeRecord = userIncomeRecordDao.checkRepeat(userId, orderId, sourceUserId, incomeType, incomeHierarchy);
        if (ObjectUtil.isNotNull(checkIncomeRecord) || NumberUtil.isLessOrEqual(amount, BigDecimal.ZERO)) {
            return;
        }
        //添加收益
        userWalletDao.addIncome(userId, amount);

        //添加记录/钱包明细
        UserIncomeRecord userIncomeRecord = new UserIncomeRecord();
        //金额
        userIncomeRecord.setAmount(amount);
        //用户
        userIncomeRecord.setUserId(userId);
        userIncomeRecord.setOrderId(orderId);
        //收益类型
        userIncomeRecord.setIncomeType(incomeType);
        userIncomeRecord.setIncomeTypeName(StrUtil.isNotBlank(remark) ? remark : incomeType.getDescription());
        //收益层级
        userIncomeRecord.setIncomeHierarchy(incomeHierarchy);
        userIncomeRecord.setIncomeHierarchyName(incomeHierarchy.getDescription());
        //订单号
        userIncomeRecord.setOrderNo(orderNo);
        //订单金额
        userIncomeRecord.setIncomeCardinality(sumAmount);
        //奖励比例
        userIncomeRecord.setIncomeProportion(ratio.toPlainString());
        userIncomeRecord.setIncomeUserNum(incomeNum);
        userIncomeRecord.setWeightsNum(weightNum);
        //来源用户
        userIncomeRecord.setSourceUserId(sourceUserId);
        userIncomeRecord.insert();

        //添加钱包明细
        UserWalletDetail userWalletDetail = new UserWalletDetail();
        userWalletDetail.setUserId(userId);
        userWalletDetail.setType(WalletDetailTypeEnum.INCOME);
        userWalletDetail.setAmount(amount);
        userWalletDetail.setCharge(BigDecimal.ZERO);
        userWalletDetail.setRealAmount(amount);
        userWalletDetail.setBeforeBalance(wallet.getBalance());
        userWalletDetail.setAfterBalance(wallet.getBalance().add(amount));
        userWalletDetail.setIsAdd(Boolean.TRUE);
        userWalletDetail.setRemark(remark);
        userWalletDetailDao.insert(userWalletDetail);
    }

    //TODO 2024-10-24 分账改造
    private void addMoneyForSplit(Long userId, Long sourceUserId, Long orderId, String
            orderNo, BigDecimal sumAmount, BigDecimal amount, BigDecimal ratio, IncomeTypeEnum
                                          incomeType, IncomeHierarchyEnum incomeHierarchy, String remark, String weightNum,
                                  String incomeNum, WalletDetailTypeEnum walletDetailTypeEnum,
                                  List<SettleAmountDTO> settleAmountDTOS, ExpenditureRecordTypeEnum expenditureRecordTypeEnum) {
        //收益幂等性校验
        UserIncomeRecord checkIncomeRecord = userIncomeRecordDao.checkRepeat(userId, orderId, sourceUserId, incomeType, incomeHierarchy);
        if (ObjectUtil.isNotNull(checkIncomeRecord) || NumberUtil.isLessOrEqual(amount, BigDecimal.ZERO)) {
            return;
        }
        //TODO 原添加收益 系统钱包
//        userWalletDao.addIncome(userId, amount);

        //添加记录/钱包明细
        UserIncomeRecord userIncomeRecord = new UserIncomeRecord();
        //金额
        userIncomeRecord.setAmount(amount);
        //用户
        userIncomeRecord.setUserId(userId);
        userIncomeRecord.setOrderId(orderId);
        //收益类型
        userIncomeRecord.setIncomeType(incomeType);
        userIncomeRecord.setIncomeTypeName(StrUtil.isNotBlank(remark) ? remark : incomeType.getDescription());
        //收益层级
        userIncomeRecord.setIncomeHierarchy(incomeHierarchy);
        userIncomeRecord.setIncomeHierarchyName(incomeHierarchy.getDescription());
        //订单号
        userIncomeRecord.setOrderNo(orderNo);
        //订单金额
        userIncomeRecord.setIncomeCardinality(sumAmount);
        //奖励比例
        userIncomeRecord.setIncomeProportion(ratio.toPlainString());
        userIncomeRecord.setIncomeUserNum(incomeNum);
        userIncomeRecord.setWeightsNum(weightNum);
        //来源用户
        userIncomeRecord.setSourceUserId(sourceUserId);
        //TODO 创建对象暂不插入数据 按需插入,非连连支付的订单不参与分账则由实际方法决定数据是否入库 此处对象只服务连连分账部分
//        userIncomeRecord.insert();

        //TODO 原添加钱包明细 组装分账对象统一处理
        SettleAmountDTO amountDTO = new SettleAmountDTO();
        amountDTO.setUserId(userId);
        amountDTO.setAmount(amount);
        amountDTO.setUserIncomeRecord(userIncomeRecord);
        amountDTO.setExpenditureRecordTypeEnum(expenditureRecordTypeEnum);
        amountDTO.setWalletDetailTypeEnum(walletDetailTypeEnum);
        settleAmountDTOS.add(amountDTO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disassemblyIncome(DisassemblyHistoryLog disassemblyHistoryLog) {

        Long collectionId = disassemblyHistoryLog.getCollectionId();
        BigDecimal disassemblySum = disassemblyHistoryLog.getDisassemblySum();
        BigDecimal startPrice = disassemblyHistoryLog.getStartPrice();

        BigDecimal settleAccountsSumAmount = BigDecimal.ZERO;
        BigDecimal chargeSum = BigDecimal.ZERO;

        DigitalCollection collection = digitalCollectionDao.getById(collectionId);
        SecondCollectionConfig secondCollectionConfig = secondCollectionConfigDao.getByCollectionId(collectionId);
        BigDecimal add = BigDecimal.ONE.add(collection.getAntiHoardRatio());
        //防囤价 = 起始价 * (1+防囤比例)
        BigDecimal initAntiHoardPrice = secondCollectionConfig.getStartPrice().multiply(add);
        //触发拆配
        //拆配规则
        // 1.防囤:   到账金额 =  防囤价 - 起始价
        // 2.防囤 并且 防囤价>拆配总价:   到账金额 = 拆配总价 - 起始价
        // 3.不防囤: 到账金额 = 拆配总价 - (拆配总价 * 手续费) - 起始价
        List<UserCollection> list = userCollectionDao.findListByCollectionId(collectionId);
        Integer settleAccountsSumUserCount = list.size();
        for (UserCollection userCollection : list) {
            //到账金额
            BigDecimal redEnvelope = BigDecimal.ZERO;
            //手续费
            BigDecimal charge = BigDecimal.ZERO;
            //拆配之前防囤价
            BigDecimal afterAntiHoardPrice = BigDecimal.ZERO;
            //拆配类型
            Integer disassemblyType = 0;

            if (userCollection.getAntiHoardFlag()) {//防囤
                if (userCollection.getAntiHoardPrice().compareTo(disassemblySum) == 1) {//防囤价大于拆配总价
                    redEnvelope = disassemblySum.subtract(startPrice);
                    disassemblyType = 2;
                } else {
                    if (userCollection.getAntiHoardPrice().compareTo(startPrice) == 1) {
                        redEnvelope = userCollection.getAntiHoardPrice().subtract(startPrice);
                    }
                    disassemblyType = 1;
                }

                afterAntiHoardPrice = userCollection.getAntiHoardPrice();

                //拆配完成之后  初始化防囤价
                userCollectionDao.updateAntiHoardPriceById(userCollection.getId(), initAntiHoardPrice);

            } else {//不防囤
                //手续费
                charge = disassemblySum.multiply(disassemblyHistoryLog.getCharge());
                redEnvelope = disassemblySum.subtract(charge).subtract(startPrice);
                disassemblyType = 3;
            }
            UserWallet userWallet = userWalletDao.getByUserId(userCollection.getUserId());

            if (redEnvelope.compareTo(BigDecimal.ZERO) == 1) {
                UserWalletDetail userWalletDetail = new UserWalletDetail();
                userWalletDetail.setUserId(userCollection.getUserId());
                userWalletDetail.setType(WalletDetailTypeEnum.DISASSEMBLE_RED_ENVELOPE);
                userWalletDetail.setAmount(redEnvelope.add(charge));
                userWalletDetail.setCharge(charge);
                userWalletDetail.setBalanceType(UserBalanceTypeEnum.PAY_BALANCE);
                userWalletDetail.setRealAmount(redEnvelope);
                userWalletDetail.setAfterBalance(userWallet.getPayBalance().add(redEnvelope));
                userWalletDetail.setBeforeBalance(userWallet.getPayBalance());
                userWalletDetail.setIsAdd(Boolean.TRUE);
                userWalletDetailDao.insert(userWalletDetail);

                DigitalCollection digitalCollection = digitalCollectionDao.getById(userCollection.getCollectionId());
                ExpenditureRecord expenditureRecord = new ExpenditureRecord();
                expenditureRecord.setUserId(userCollection.getUserId());
                expenditureRecord.setAmount(redEnvelope.add(charge));
                expenditureRecord.setCharge(charge);
                expenditureRecord.setRealAmount(redEnvelope);
                expenditureRecord.setType(ExpenditureRecordTypeEnum.RED_PACKET);
                expenditureRecord.setBeforeBalance(userWallet.getPayBalance());
                expenditureRecord.setAfterBalance(userWallet.getPayBalance().add(redEnvelope));
                expenditureRecord.setRemark(digitalCollection.getFirstTitle() + " 拆配");
                expenditureRecordDao.insert(expenditureRecord);
                //加钱
                userWalletDao.addPayBalance(userCollection.getUserId(), redEnvelope);

                //添加拆配明细
                DisassemblyDetailsLog disassemblyDetailsLog = new DisassemblyDetailsLog();
                disassemblyDetailsLog.setUserId(userCollection.getUserId());
                disassemblyDetailsLog.setUserCollectionId(userCollection.getId());
                disassemblyDetailsLog.setCharge(charge);
                disassemblyDetailsLog.setDisassemblyAmount(redEnvelope);
                disassemblyDetailsLog.setAfterBuyPrice(userCollection.getBuyPrice());
                disassemblyDetailsLog.setAfterAntiHoardPrice(afterAntiHoardPrice);
                disassemblyDetailsLog.setBeforeBuyPrice(userCollection.getBuyPrice());
                disassemblyDetailsLog.setBeforeAntiHoardPrice(initAntiHoardPrice);
                disassemblyDetailsLog.setDisassemblyAntiHoardFlag(userCollection.getAntiHoardFlag());
                disassemblyDetailsLog.setDisassemblyType(disassemblyType);
                disassemblyDetailsLog.setDisassemblySum(disassemblySum);
                disassemblyDetailsLog.insert();

                //更新拆配总金额
                userCollectionDao.addDisassemblyAmountById(redEnvelope, userCollection.getId());

                settleAccountsSumAmount = settleAccountsSumAmount.add(redEnvelope);
                chargeSum = chargeSum.add(charge);
            }

        }
        disassemblyHistoryLog.setDisassemblySum(settleAccountsSumAmount);
        disassemblyHistoryLog.setChargeSum(chargeSum);
        disassemblyHistoryLog.setIsSettleAccounts(Boolean.TRUE);
        disassemblyHistoryLog.updateById();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void serviceCenterDividends(DaoShareConfig daoShareConfig, String yearWeek) {
        List<SharePoolWeek> sharePoolWeeks = sharePoolWeekDao.getWaitSettleByType(daoShareConfig.getDaoId(), yearWeek, daoShareConfig.getAwardsType());
        if (CollUtil.isEmpty(sharePoolWeeks)) {
            return;
        }
        List<UserCityServerCentre> cityServerCentres = userCityServerCentreDao.list();
        if (CollUtil.isEmpty(cityServerCentres)) {
            return;
        }
        List<Long> userIds = cityServerCentres.stream().map(UserCityServerCentre::getUserId).collect(Collectors.toList());
        List<TeamUserPerformanceDTO> userHoldMarketList = Lists.newArrayList();
        for (Long userId : userIds) {
            List<Long> downCityServiceList = userCityServerCentreDao.getNextServiceCity(userId);
            BigDecimal holdMarketValue = userMarketValueDao.getMarketValue(userId, downCityServiceList);
            if (NumberUtil.isGreater(holdMarketValue, BigDecimal.ZERO)) {
                TeamUserPerformanceDTO teamUserPerformanceDTO = new TeamUserPerformanceDTO();
                teamUserPerformanceDTO.setUserId(userId);
                teamUserPerformanceDTO.setSumPerformance(holdMarketValue);
                userHoldMarketList.add(teamUserPerformanceDTO);
            }
        }
        BigDecimal sumWeight = userHoldMarketList.stream().map(TeamUserPerformanceDTO::getSumPerformance).reduce(BigDecimal::add).get();

        BigDecimal thisWeekSumAmount = BigDecimal.ZERO;
        for (SharePoolWeek sharePoolWeek : sharePoolWeeks) {
            if (NumberUtil.isGreater(sharePoolWeek.getSumAmount(), BigDecimal.ZERO)) {
                thisWeekSumAmount = thisWeekSumAmount.add(sharePoolWeek.getSumAmount().multiply(getDivRatio()).setScale(2, RoundingMode.FLOOR));
            }
            sharePoolWeek.setIsSettle(true);
            sharePoolWeek.updateById();
        }
        for (TeamUserPerformanceDTO teamUserPerformanceDTO : userHoldMarketList) {
            BigDecimal ratio = teamUserPerformanceDTO.getSumPerformance().divide(sumWeight, 8, RoundingMode.FLOOR);
            BigDecimal sumAmount = thisWeekSumAmount.multiply(ratio).setScale(2, RoundingMode.FLOOR);
            BigDecimal balance = sumAmount.multiply(BigDecimal.valueOf(0.8)).setScale(2, RoundingMode.FLOOR);
            BigDecimal wishBalance = sumAmount.subtract(balance);
            IncomeTypeEnum incomeType = IncomeTypeEnum.CITY_SERVER;
            IncomeHierarchyEnum incomeHierarchy = IncomeHierarchyEnum.SPECIAL;
            UserWallet wallet = userWalletDao.getByUserId(teamUserPerformanceDTO.getUserId());
            addMoney(teamUserPerformanceDTO.getUserId(), wallet, daoShareConfig.getId(), Long.parseLong(yearWeek), null,
                    thisWeekSumAmount, balance, ratio, incomeType, incomeHierarchy, daoShareConfig.getName(), sumWeight.toPlainString(), teamUserPerformanceDTO.getSumPerformance().toPlainString());
            addWishMoney(teamUserPerformanceDTO.getUserId(), wallet, wishBalance, daoShareConfig.getName());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void serviceCenterLevel(DaoShareConfig daoShareConfig, String yearWeek) {
        List<SharePoolWeek> sharePoolWeeks = sharePoolWeekDao.getWaitSettleByType(daoShareConfig.getDaoId(), yearWeek, daoShareConfig.getAwardsType());
        if (CollUtil.isEmpty(sharePoolWeeks)) {
            return;
        }
        List<UserCityServerCentre> cityServerCentres = userCityServerCentreDao.list();
        if (CollUtil.isEmpty(cityServerCentres)) {
            return;
        }
        Map<Long, Integer> userRatio = Maps.newHashMap();
        for (UserCityServerCentre cityServerCentre : cityServerCentres) {
            Long upUserId = userCityServerCentreDao.accessTheNearestCityServiceCenter(cityServerCentre.getUserId());
            if (ObjectUtil.isNotNull(upUserId)) {
                if (userRatio.containsKey(upUserId)) {
                    userRatio.put(upUserId, userRatio.get(upUserId) + 1);
                } else {
                    userRatio.put(upUserId, 1);
                }
            }

        }
        int sumWeight = 0;
        for (Map.Entry<Long, Integer> entry : userRatio.entrySet()) {
            sumWeight += entry.getValue();
        }
        BigDecimal thisWeekSumAmount = BigDecimal.ZERO;
        for (SharePoolWeek sharePoolWeek : sharePoolWeeks) {
            if (NumberUtil.isGreater(sharePoolWeek.getSumAmount(), BigDecimal.ZERO)) {
                thisWeekSumAmount = thisWeekSumAmount.add(sharePoolWeek.getSumAmount().multiply(getDivRatio()).setScale(2, RoundingMode.FLOOR));
            }
            sharePoolWeek.setIsSettle(true);
            sharePoolWeek.updateById();
        }
        for (Map.Entry<Long, Integer> entry : userRatio.entrySet()) {
            BigDecimal ratio = BigDecimal.valueOf(entry.getValue()).divide(BigDecimal.valueOf(sumWeight), 8, RoundingMode.FLOOR);
            BigDecimal sumAmount = thisWeekSumAmount.multiply(ratio).setScale(2, RoundingMode.FLOOR);
            BigDecimal balance = sumAmount.multiply(BigDecimal.valueOf(0.8)).setScale(2, RoundingMode.FLOOR);
            BigDecimal wishBalance = sumAmount.subtract(balance);
            IncomeTypeEnum incomeType = IncomeTypeEnum.URBAN_EXTENSION_DIVIDEND;
            IncomeHierarchyEnum incomeHierarchy = IncomeHierarchyEnum.SPECIAL;

            UserWallet wallet = userWalletDao.getByUserId(entry.getKey());
            addMoney(entry.getKey(), wallet, daoShareConfig.getId(), Long.parseLong(yearWeek), null,
                    thisWeekSumAmount, balance, ratio, incomeType, incomeHierarchy, daoShareConfig.getName(), String.valueOf(sumWeight), entry.getValue().toString());
            addWishMoney(entry.getKey(), wallet, wishBalance, daoShareConfig.getName());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void workRoomDividends(DaoShareConfig daoShareConfig, String yearWeek) {
        List<SharePoolWeek> sharePoolWeeks = sharePoolWeekDao.getWaitSettleByType(daoShareConfig.getDaoId(), yearWeek, daoShareConfig.getAwardsType());
        if (CollUtil.isEmpty(sharePoolWeeks)) {
            return;
        }
        List<UserWorkRoom> userIds = userWorkRoomDao.list();
        List<TeamIncomeDTO> list = Lists.newArrayList();
        for (UserWorkRoom userWorkRoom : userIds) {
            List<Long> cityIds = userRelevanceDao.getNearCityServer(userWorkRoom.getUserId());
            List<Long> workIds = userRelevanceDao.getNearWorkRoom(userWorkRoom.getUserId());
            BigDecimal sumMarketValue = userMarketValueDao.getMarketValue(userWorkRoom.getUserId(), CollUtil.addAllIfNotContains(cityIds, workIds));
            if (NumberUtil.equals(sumMarketValue, BigDecimal.ZERO)) {
                log.warn("用户{}团队持仓为零", userWorkRoom.getUserId());
                continue;
            }
            TeamIncomeDTO teamIncomeDTO = new TeamIncomeDTO();
            teamIncomeDTO.setUserId(userWorkRoom.getUserId());
            teamIncomeDTO.setTotalTransaction(sumMarketValue);
            list.add(teamIncomeDTO);
        }
        BigDecimal sumWeight = list.stream().map(TeamIncomeDTO::getTotalTransaction).reduce(BigDecimal::add).get();
        BigDecimal thisWeekSumAmount = BigDecimal.ZERO;
        for (SharePoolWeek sharePoolWeek : sharePoolWeeks) {
            if (NumberUtil.isGreater(sharePoolWeek.getSumAmount(), BigDecimal.ZERO)) {
                thisWeekSumAmount = thisWeekSumAmount.add(sharePoolWeek.getSumAmount().multiply(getDivRatio()).setScale(2, RoundingMode.FLOOR));
            }
            sharePoolWeek.setIsSettle(true);
            sharePoolWeek.updateById();
        }
        for (TeamIncomeDTO teamIncomeDTO : list) {
            BigDecimal ratio = teamIncomeDTO.getTotalTransaction().divide(sumWeight, 8, RoundingMode.FLOOR);
            BigDecimal sumAmount = thisWeekSumAmount.multiply(ratio).setScale(2, RoundingMode.FLOOR);
            BigDecimal balance = sumAmount.multiply(BigDecimal.valueOf(0.8)).setScale(2, RoundingMode.FLOOR);
            BigDecimal wishBalance = sumAmount.subtract(balance);
            IncomeTypeEnum incomeType = IncomeTypeEnum.COMMUNITY_DIVIDEND;
            IncomeHierarchyEnum incomeHierarchy = IncomeHierarchyEnum.SPECIAL;
            UserWallet wallet = userWalletDao.getByUserId(teamIncomeDTO.getUserId());
            addMoney(teamIncomeDTO.getUserId(), wallet, daoShareConfig.getId(), Long.parseLong(yearWeek), null,
                    thisWeekSumAmount, balance, ratio, incomeType, incomeHierarchy, daoShareConfig.getName(), sumWeight.toPlainString(), teamIncomeDTO.getTotalTransaction().toPlainString());
            addWishMoney(teamIncomeDTO.getUserId(), wallet, wishBalance, daoShareConfig.getName());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cultivationAward(DaoShareConfig config, String yearWeek) {
        List<SharePoolWeek> sharePoolWeeks = sharePoolWeekDao.getWaitSettleByType(config.getDaoId(), yearWeek, config.getAwardsType());
        if (CollUtil.isEmpty(sharePoolWeeks)) {
            return;
        }
        List<Long> userIds = userCollectionDao.getUserIdByHoldCollectionId(config.getIdentityCollectionId());
        int sumCount = 0;
        List<NurturingAwardIncomeDTO> list = Lists.newArrayList();
        for (Long userId : userIds) {
            List<Long> holdUsers = userCollectionDao.getJuniorHoldCollectionCountByCollectionIds(userId, Lists.newArrayList(config.getPushCollectionId()));
            if (holdUsers.size() >= config.getHoldUserCount()) {
                NurturingAwardIncomeDTO nurturingAwardIncomeDTO = new NurturingAwardIncomeDTO();
                nurturingAwardIncomeDTO.setUserId(userId);
                nurturingAwardIncomeDTO.setCount(holdUsers.size());
                list.add(nurturingAwardIncomeDTO);
                sumCount += nurturingAwardIncomeDTO.getCount();
            }

        }
        BigDecimal thisWeekSumAmount = BigDecimal.ZERO;
        for (SharePoolWeek sharePoolWeek : sharePoolWeeks) {
            if (NumberUtil.isGreater(sharePoolWeek.getSumAmount(), BigDecimal.ZERO)) {
                thisWeekSumAmount = thisWeekSumAmount.add(sharePoolWeek.getSumAmount().multiply(getDivRatio()).setScale(2, RoundingMode.FLOOR));
            }
            sharePoolWeek.setIsSettle(true);
            sharePoolWeek.updateById();
        }
        for (NurturingAwardIncomeDTO nurturingAwardIncomeDTO : list) {
            BigDecimal ratio = BigDecimal.valueOf(nurturingAwardIncomeDTO.getCount()).divide(BigDecimal.valueOf(sumCount), 8, RoundingMode.FLOOR);
            BigDecimal sumAmount = thisWeekSumAmount.multiply(ratio).setScale(2, RoundingMode.FLOOR);
            BigDecimal balance = sumAmount.multiply(BigDecimal.valueOf(0.8)).setScale(2, RoundingMode.FLOOR);
            BigDecimal wishBalance = sumAmount.subtract(balance);
            IncomeTypeEnum incomeType = IncomeTypeEnum.NURTURING_AWARD;
            IncomeHierarchyEnum incomeHierarchy = IncomeHierarchyEnum.SPECIAL;
            UserWallet wallet = userWalletDao.getByUserId(nurturingAwardIncomeDTO.getUserId());
            addMoney(nurturingAwardIncomeDTO.getUserId(), wallet, config.getId(), Long.parseLong(yearWeek), null,
                    thisWeekSumAmount, balance, ratio, incomeType, incomeHierarchy, config.getName(), String.valueOf(sumCount), String.valueOf(nurturingAwardIncomeDTO.getCount()));
            addWishMoney(nurturingAwardIncomeDTO.getUserId(), wallet, wishBalance, config.getName());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void positionReward(DaoShareConfig daoShareConfig, String yearWeek) {
        List<SharePoolWeek> sharePoolWeeks = sharePoolWeekDao.getWaitSettleByTypeAndCollectionId(daoShareConfig.getDaoId(), yearWeek, daoShareConfig.getAwardsType(), daoShareConfig.getIdentityCollectionId(), daoShareConfig.getPushCollectionId());
        if (CollUtil.isEmpty(sharePoolWeeks)) {
            log.info("[{}] positionReward sharePoolWeeks is empty", JSONObject.toJSONString(daoShareConfig));
            return;
        }
        List<Long> userIds = userCollectionDao.getUserIdByCollectionId(daoShareConfig.getIdentityCollectionId());//藏品流通数
        if (CollectionUtils.isEmpty(userIds)) {
            log.info("[{}]positionReward userIds is empty", JSONObject.toJSONString(daoShareConfig));
            return;
        }
        Map<Long, Integer> userIdCountMap = userIds.stream().collect(Collectors.toMap(id -> id, id -> 1, Integer::sum));//用户持有数

        int sumCount = 0;
        List<NurturingAwardIncomeDTO> list = Lists.newArrayList();
        for (Map.Entry<Long, Integer> um : userIdCountMap.entrySet()) {
            Long key = um.getKey();
            Integer value = um.getValue();
            NurturingAwardIncomeDTO nai = new NurturingAwardIncomeDTO();
            nai.setUserId(key);
            nai.setCount(value);
            list.add(nai);
            sumCount += nai.getCount();
        }

        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal allAmount = BigDecimal.ZERO;
        for (SharePoolWeek sharePoolWeek : sharePoolWeeks) {
            if (!NumberUtil.isGreater(sharePoolWeek.getSumAmount(), BigDecimal.ZERO)) {
                continue;
            }
            if (sharePoolWeek.getMarketLevel() == MarketLevelEnum.FIRST) {
                BigDecimal firstResult = sharePoolWeek.getSumAmount().divide(new BigDecimal(userIds.size()), 2, RoundingMode.FLOOR);
                amount = amount.add(firstResult);
                allAmount = allAmount.add(sharePoolWeek.getSumAmount());
            }
            if (sharePoolWeek.getMarketLevel() == MarketLevelEnum.SECOND) {
                BigDecimal secondResult = sharePoolWeek.getSumAmount().divide(new BigDecimal(userIds.size()), 2, RoundingMode.FLOOR);
                amount = amount.add(secondResult);
                allAmount = allAmount.add(sharePoolWeek.getSumAmount());
            }
            sharePoolWeek.setIsSettle(true);
            sharePoolWeek.updateById();
        }
        if (!NumberUtil.isGreater(amount, BigDecimal.ZERO)) {//如果分的金额为0直接不分
            log.info("[{}]positionReward amount is Zero", JSONObject.toJSONString(daoShareConfig));
            return;
        }
        for (NurturingAwardIncomeDTO nai : list) {
            BigDecimal ratio = BigDecimal.valueOf(nai.getCount()).divide(Convert.toBigDecimal(userIds.size()), 4, RoundingMode.FLOOR);
            IncomeTypeEnum incomeType = IncomeTypeEnum.POSITION_REWARD;
            IncomeHierarchyEnum incomeHierarchy = IncomeHierarchyEnum.SPECIAL;
            UserWallet wallet = userWalletDao.getByUserId(nai.getUserId());
            BigDecimal result = amount.multiply(new BigDecimal(nai.getCount())).setScale(2, RoundingMode.FLOOR);
            addMoney(nai.getUserId(), wallet, daoShareConfig.getId(), Long.parseLong(yearWeek), null, allAmount, result, ratio, incomeType, incomeHierarchy, daoShareConfig.getName(), String.valueOf(sumCount), String.valueOf(nai.getCount()));
        }
    }

}
